<!DOCTYPE html>
<html>

<head>
  <meta charset=utf-8>
  <meta name=viewport content="width=device-width,initial-scale=1">
  <title>可视化生成代码配置</title>
  <style>
    * {
      padding: 0;
      margin: 0;
      box-sizing: border-box;
      font-family: "Microsoft Yahei";
    }

    *::-webkit-scrollbar {
      width: 4px;
      height: 4px;
      scrollbar-arrow-color: red;

    }

    *::-webkit-scrollbar-thumb {
      border-radius: 5px;
      -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
      background: rgba(0, 0, 0, 0.2);
      scrollbar-arrow-color: red;
    }

    *::-webkit-scrollbar-track {
      -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
      border-radius: 0;
      background: rgba(0, 0, 0, 0.1);
    }

    body {
      background: #f9f9f9;
      font-size: 14px;
      color: #1e2227;
      overflow: hidden;
      padding: 0;
      margin: 0;
    }

    .require {
      position: relative;
    }

    .require::after {
      content: '*';
      color: red;
      position: absolute;
      left: -12px;
    }

    .button {
      background: #fff;
      border: none;
      box-shadow: 0 0 5px 0 #ccc;
      border-radius: 5px;
      cursor: pointer;
      padding: 4px 16px;
      margin-left: 15px;
      margin-top: 8px;
      user-select: none;
    }

    .input {
      padding: 0 16px;
      height: 32px;
      line-height: 32px;
      border-radius: 3px;
      border: 1px solid #ccc;
      outline: none;
      font-size: 12px;
      color: #1e2227;
      width: 100%;
    }

    .input>option {
      padding: 8px 12px;
    }

    .select {
      padding: 0 16px;
      height: 32px;
      line-height: 32px;
      border-radius: 3px;
      border: 1px solid #ccc;
      outline: none;
      text-align: right;
      font-size: 12px;
      color: #1e2227;
      width: 100%;
    }

    .dateTime {
      padding: 0 16px;
      height: 32px;
      line-height: 32px;
      border-radius: 3px;
      border: 1px solid #ccc;
      outline: none;
      text-align: left;
      font-size: 12px;
      color: #1e2227;
      position: relative;
      width: 100%;
      text-align: center;
    }

    .dateTime>svg {
      position: absolute;
      left: 8px;
      top: 6px;
    }

    .dateSelect {
      padding: 0 16px;
      height: 32px;
      line-height: 32px;
      border-radius: 3px;
      border: 1px solid #ccc;
      outline: none;
      text-align: left;
      font-size: 12px;
      color: #1e2227;
      position: relative;
      width: 100%;
      text-align: center;
    }

    .dateSelect>svg {
      position: absolute;
      left: 8px;
      top: 6px;
    }

    .timeSelect {
      padding: 0 16px;
      height: 32px;
      line-height: 32px;
      border-radius: 3px;
      border: 1px solid #ccc;
      outline: none;
      text-align: left;
      font-size: 12px;
      color: #1e2227;
      position: relative;
      width: 100%;
      text-align: center;
    }

    .timeSelect>svg {
      position: absolute;
      left: 8px;
      top: 6px;
    }

    .switch {
      background: #dcdfe6;
      width: 55px;
      height: 26px;
      border-radius: 25px;
      position: relative;
    }

    .switch .dot {
      background: #fff;
      width: 24px;
      height: 24px;
      border-radius: 28px;
      position: relative;
      top: 1px;
      left: 2px;
    }

    .checkBox>label {
      vertical-align: middle;
      display: inline-block;
      user-select: none;
    }

    .checkBox>label>input {
      margin-right: 3px;
      margin-left: 5px;
      vertical-align: middle;
    }

    .radio>label {
      vertical-align: middle;
      display: inline-block;
      user-select: none;
    }

    .radio>label>input {
      margin-right: 3px;
      margin-left: 5px;
      vertical-align: middle;
    }

    .textarea {
      padding: 0 16px;
      height: 64px;
      line-height: 64px;
      border-radius: 3px;
      border: 1px solid #ccc;
      outline: none;
      font-size: 12px;
      color: #1e2227;
      width: 100%;
    }

    .buttonGroup {
      display: flex;
      align-items: center;
    }

    .el-button {
      padding: 12px;
      width: 80px;
      background: #fff;
      font-weight: 500;
      padding: 8px 20px;
      border: 1px solid #dcdfe6;
      border-radius: 4px;
      color: #606266;
      text-align: center;
      margin: 0 5px;
    }

    .el-button[type=primary] {
      background: #409eff;
      color: #fff;
    }

    #dialogsModelDom {
      position: fixed;
      width: 450px;
      box-shadow: 0 0 5px 0 #ccc;
      left: 50%;
      top: 30%;
      transform: translate(-50%, -50%);
      z-index: 3;
      background: #fff;
      color: #1e2227;
      border-radius: 5px;
      padding: 18px 30px;
    }

    .model-btns {
      text-align: right;
      padding-top: 18px;
    }

    .mask {
      position: fixed;
      left: 0;
      top: 0;
      width: 100vw;
      height: 100vh;
      background: #23272e;
      opacity: 0.5;
      z-index: 2;
    }

    #dialogContent {
      padding: 18px 12px;
    }

    #dialogTitle {
      color: #1e2227;
      font-weight: 600;
      font-size: 18px;
    }

    .message {
      position: fixed;
      top: 60px;
      left: 50%;
      transform: translate(-50%, -50%);
      padding: 14px 24px;
      font-size: 15px;
      width: 460px;
      border-radius: 5px;
      user-select: none;
    }

    #errorMsg {
      color: #f56c6c;
      background: #f1e1e1;
    }

    #successMsg {
      color: #67c23a;
      background: #e2e9df;
    }

    #app {
      display: flex;
      width: 100vw;
      height: calc(100vh - 79px);
      overflow: hidden;
    }

    .app-items {
      flex: 1;
      padding: 25px 12px;
      overflow-y: auto;
    }

    .app-items .title {
      margin-bottom: 18px;
    }

    .modules .module-item {
      display: flex;
      align-items: center;
      padding: 12px 20px;
      position: relative;
    }

    .modules .module-item:hover::after {
      content: "";
      position: absolute;
      width: 100%;
      height: 100%;
      left: 0;
      top: 0;
      border: 1px dashed #ccc;
      cursor: pointer;
    }

    .modules .module-item.active {
      box-shadow: inset 0 0 5px 0 #ccc;
      border-radius: 5px;
    }

    .modules .module-item.active:hover::after {
      content: "";
      position: absolute;
      width: 0;
      height: 0;
    }

    .modules .module-item .label {
      font-weight: 600;
      width: 85px;
      flex-shrink: 0;
      overflow-x: hidden;
      text-overflow: ellipsis;
    }

    .modules .module-item .label.buttonGroup-label {
      width: 130px;
    }

    .modules .module-item .model {
      flex: 1;
    }

    #preview-box {
      border-left: 1px solid #ddd;
      border-right: 1px solid #ddd;
    }

    .configuration-item.btn-group>span {
      text-align: center;
    }

    .configuration-item.btn-group>* {
      flex: 1;
      flex-direction: 0;
    }

    .configuration-item {
      display: flex;
      align-items: center;
      padding: 12px 20px;
    }

    .configuration-item .label {
      width: 90px;
      font-weight: 600;
    }

    .configuration-item .val {
      flex: 1;
    }

    .config-btn {
      text-align: right;
      margin-top: 18px;
    }

    .update-preview {
      text-align: right;
      height: 60px;
      line-height: 60px;
      padding: 0 25px;
      border-top: 1px solid #ddd;
    }
  </style>
</head>

<body>
  <div id=app>
    <!-- 组件区 -->
    <div id="modules-box" class="app-items">
      <h2 class="title">组件选择</h2>
      <div class="modules"></div>
    </div>
    <!-- 预览区 -->
    <div id="preview-box" class="app-items">
      <h2 class="title">效果预览</h2>
      <div id="preview-area" class="modules"></div>
    </div>
    <!-- 属性配置区 -->
    <div class="app-items">
      <h2 class="title">属性配置</h2>
      <div id="configuration"></div>
      <div class="config-btn">
        <button class="button" onclick="removePreviewArea()">删除当前选中元素</button>
        <button class="button" onclick="onChangeAttr()">确认修改</button>
      </div>
    </div>
  </div>
  <div class="update-preview">
    <button class="button" onclick="onGenerateCode()">生成代码</button>
  </div>

  <div class="mask dialogsModel" style="display: none;" onclick="onDialogCancel()"></div>
  <div style="display: none;" class="dialogsModel" id="dialogsModelDom">
    <div id="dialogTitle"></div>
    <div id="dialogContent"></div>
    <div class="model-btns">
      <button class="button model-btn" onclick="onDialogConfirm()">确 认</button>
      <button class="button model-btn" onclick="onDialogCancel()">取 消</button>
    </div>
  </div>
  <div id="errorMsg" style="display: none;" class="message"></div>
  <div id="successMsg" style="display: none;" class="message"></div>

  <script>
    // 生成的code
    var codeStr = `
<template>
  <div class="create-edit-module-box">
    <div class="form-wrap">
      <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="120px">
        __$template
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  name: 'CreateEditModule',
  props: {
    isEdit: {
      type: Boolean,
      default: () => false
    }
  },
  data() {
    return {
      __$data
    }
  },
  methods: __$methods
}
<\/script>

<style scoped lang="scss">
.create-edit-module-box{
  .form-wrap{
    width: 600px;
    margin: 30px auto;
  }
}
</style>

    `
    var __$template = ''
    var __$data = ''
    var __$methods = ''
    // message 定时器对象
    var messgaeClock = null
    // dialog 弹窗的发布订阅, 此字段用于储存事件队列
    var dialogObj = {
      title: '',  // 标题
      content: '', // 内容
      success: null, // 确认 click event
      fail: null // 取消 click event
    }
    // 当前选中的元素
    var currentActiveIndex = null
    // 预览 preview 中所有的dom元素
    var previewDomList = []
    // 组件渲染的dom对象
    const moduleDom = {
      input: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label：</div> <div class="input model"></div> </div>`,
      select: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label: </div> <div class="select model"> <svg t="1672380398335" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3458" width="15" height="15"> <path d="M787.2 380.8c-9.6-9.6-22.4-12.8-35.2-12.8l-480 3.2c-12.8 0-25.6 3.2-35.2 12.8-19.2 19.2-19.2 48 0 67.2l240 240c0 0 0 0 0 0 0 0 0 0 0 0 3.2 3.2 9.6 6.4 12.8 9.6 0 0 3.2 3.2 3.2 3.2 16 6.4 38.4 3.2 51.2-9.6l240-243.2C806.4 428.8 803.2 400 787.2 380.8z" p-id="3459"></path> </svg> </div>`,
      dateTime: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label: </div> <div class="dateTime model"> <svg t="1672398249238" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4576" width="20" height="20"><path d="M390.784 128l-0.064 44.416h234.176V128h64v44.416h198.08V832H128V172.416h198.72V128h64zM326.72 235.584l-135.488 0.064v533.12h632.512v-533.12l-134.848-0.064v59.904h-64v-59.904H390.72v59.904h-64v-59.904z m202.432 216.96v254.4h53.888v32.384H426.88v-32.384h59.648V527.68l0.192-9.664 0.448-9.856-45.952 38.784-3.008 1.92-3.072 1.152a13.056 13.056 0 0 1-5.76 0.128 15.296 15.296 0 0 1-4.736-1.92 11.776 11.776 0 0 1-3.264-2.88l-13.376-18.688 86.272-74.112h34.816z m226.816-106.24v64H259.008v-64h496.96z" fill="#A7A3A2" p-id="4577"></path></svg> 至 </div>`,
      dateSelect: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label: </div> <div class="dateSelect model"> <svg t="1672398249238" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4576" width="20" height="20"><path d="M390.784 128l-0.064 44.416h234.176V128h64v44.416h198.08V832H128V172.416h198.72V128h64zM326.72 235.584l-135.488 0.064v533.12h632.512v-533.12l-134.848-0.064v59.904h-64v-59.904H390.72v59.904h-64v-59.904z m202.432 216.96v254.4h53.888v32.384H426.88v-32.384h59.648V527.68l0.192-9.664 0.448-9.856-45.952 38.784-3.008 1.92-3.072 1.152a13.056 13.056 0 0 1-5.76 0.128 15.296 15.296 0 0 1-4.736-1.92 11.776 11.776 0 0 1-3.264-2.88l-13.376-18.688 86.272-74.112h34.816z m226.816-106.24v64H259.008v-64h496.96z" fill="#A7A3A2" p-id="4577"></path></svg> </div>`,
      timeSelect: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label: </div> <div class="timeSelect model"> <svg t="1672901821833" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3568" width="20" height="20"><path d="M949.638897 509.757936c0-241.799068-196.006116-437.805184-437.805184-437.805184-241.800092 0-437.806207 196.006116-437.806207 437.805184 0 241.811348 196.006116 437.817464 437.806207 437.817464 99.262748 0 190.149734-33.771151 263.59242-89.425705 3.015683-3.421936 4.999874-7.789407 4.999874-12.698207 0-10.717086-8.692986-19.407002-19.408025-19.407002-5.562692 0-10.513448 2.207271-14.048971 5.944386l-0.246617 0c-65.719794 48.358381-146.610102 77.313853-234.459916 77.313853-218.947618 0-396.469754-177.544649-396.469754-396.482033 0-218.97013 177.522136-396.470777 396.469754-396.470777 218.969107 0 396.469754 177.500647 396.469754 396.470777 0 66.865897-15.692401 129.814578-44.962028 185.110975l0 0.325411c-0.538259 1.845021-1.12359 3.645017-1.12359 5.627161 0 10.719132 8.688893 19.407002 19.407002 19.407002 8.353248 0 15.331173-5.357008 18.055215-12.742209l0 0.135076C931.289993 650.424676 949.638897 582.250994 949.638897 509.757936zM506.813373 276.017404c0-11.527544-9.367345-20.892843-20.917402-20.892843-11.527544 0-20.892843 9.365298-20.892843 20.892843l0 248.508887c0 0-2.520403 42.010813 41.786709 41.785685L731.994971 566.311976c0.068562 0 0.156566 0.045025 0.228197 0.045025 11.546987 0 20.914332-9.364275 20.914332-20.891819s-9.367345-20.892843-20.892843-20.938891L506.79086 524.526291 506.79086 276.153504C506.79086 276.108478 506.813373 276.06243 506.813373 276.017404z" fill="#A8A8A8" p-id="3569"></path></svg> </div>`,
      switch: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label: </div> <div class="switch"> <div class="dot"></div> </div>`,
      checkBox: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label: </div> <div class="checkBox model"> <label><input name="checkBoxOption" type="checkbox" value="" />多选选项一 </label> <label><input name="checkBoxOption" type="checkbox" value="" />多选选项二 </label> </div>`,
      radio: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label: </div> <div class="radio model"> <label><input name="checkBoxOption" type="radio" value="" />单选选项一 </label> <label><input name="checkBoxOption" type="radio" value="" />单选选项二 </label> </div>`,
      textarea: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label">$label：</div> <div class="textarea model"></div> </div>`,
      buttonGroup: `<div class="module-item" index="$index" onclick="$clickEvent"> <div class="label buttonGroup-label">$label: </div> <div class="buttonGroup model"> <div class="el-button" type="primary">提交</div> <div class="el-button">取消</div> </div>`,
    }
    // 属性渲染的dom对象
    const configDom = {
      label: `<div class="configuration-item"> <div class="label">label：</div> <div class="val"><input type="text" value="$value" class="input" data-key="label" placeholder="请输入label值" /></div> </div>`,
      model: `<div class="configuration-item"> <div class="require label">model：</div> <div class="val"><input type="text" value="$value" data-key="model" class="input" placeholder="请输入双向绑定的字段" /></div> </div>`,
      data: `<div class="configuration-item"> <div class="label">数据源：</div> <div class="val"><input type="text" value="$value" data-key="data" class="input" placeholder="请输入数据源的字段" /></div> </div>`,
      placeholder: `<div class="configuration-item"> <div class="label">占位符：</div> <div class="val"><input type="text" value="$value" data-key="placeholder" class="input" placeholder="请输入占位符" /></div> </div>`,
      startPlaceholder: `<div class="configuration-item"> <div class="label">开始占位符：</div> <div class="val"><input type="text" value="$value" data-key="startPlaceholder" class="input" placeholder="请输入开始占位符" /></div> </div>`,
      endPlaceholder: `<div class="configuration-item"> <div class="label">结束占位符：</div> <div class="val"><input type="text" value="$value" data-key="endPlaceholder" class="input" placeholder="请输入结束占位符" /></div> </div>`,
      btns: `<div class="configuration-item push-btn-group button" onclick="onPushBtnInBtns()"> 往按钮组中新增一个按钮 </div>`,
      btnItem: `<div class="configuration-item btn-group">
        <span>名称：</span><input type="text" value="$nameValue" data-key="btnItem" class="input" data-key="btnName" placeholder="请输入按钮名称" />
        <span>类型：</span>
        <select class="input" data-key="btnType" value="$typeValue" placeholder="请输入按钮类型">
          <option value="default">default</option>
          <option value="primary">primary</option> 
        </select>  
        <div class="button" style="flex: 0.8; font-size: 12px;text-align: center;margin-top: 0;" index="$index" onclick="onRemoveBtnItem(this)">删除</div>
      </div>`,
    }
    // 枚举, 控制选中的对象应该有哪些属性配置项
    const selectorEnum = {
      input: ['label', 'model', 'placeholder'],
      select: ['label', 'model', 'data', 'placeholder'],
      dateTime: ['label', 'model', 'startPlaceholder', 'endPlaceholder'],
      dateSelect: ['label', 'model', 'placeholder'],
      timeSelect: ['label', 'model', 'placeholder'],
      switch: ['label', 'model'],
      checkBox: ['label', 'model', 'data'],
      radio: ['label', 'model', 'data'],
      textarea: ['label', 'model', 'placeholder'],
      buttonGroup: ['btns']
    }

    // 类
    class Message {
      success(msg) {
        const successMsg = document.querySelector('#successMsg')
        successMsg.style.display = 'block'
        successMsg.innerHTML = msg.content || msg
        if (messgaeClock) clearTimeout(messgaeClock)
        messgaeClock = setTimeout(() => {
          successMsg.style.display = 'none'
          messgaeClock = null
        }, msg.delay || 3000)
      }
      error(msg) {
        const errorMsg = document.querySelector('#successMsg')
        successMsg.style.display = 'block'
        successMsg.innerHTML = msg.content || msg
        if (messgaeClock) clearTimeout(messgaeClock)
        messgaeClock = setTimeout(() => {
          successMsg.style.display = 'none'
          messgaeClock = null
        }, msg.delay || 3000)
      }
    }
    this.$message = new Message()

    class Create {
      template(item) {
        let result = `<el-form-item label="${item.label}" prop="${item.model}">`
        if (item.label === 'buttonGroup') result = `<el-form-item>`
        switch (item.type) {
          case 'input':
            result += `<el-input v-model="ruleForm.${item.model}" placeholder="${item.placeholder}"></el-input>`
            break;
          case 'select':
            if (item.data) {
              result += `<el-select v-model="ruleForm.${item.model}" placeholder="${item.placeholder}"> <el-option v-for="(item, index) in ${item.data}" :key="index" :label="item.label" :value="${item.value}" /> </el-select>`
            } else {
              result += `<el-select v-model="ruleForm.${item.model}" placeholder="${item.placeholder}"> <el-option label="label1" value="value1"></el-option> </el-select>`
            }
            break;
          case 'dateTime':
            result += `<el-date-picker v-model="ruleForm.${item.model}" type="datetimerange" range-separator="至" start-placeholder="${item.startPlaceholder}" end-placeholder="${item.endPlaceholder}" />`
            break;
          case 'dateSelect':
            result += `<el-date-picker v-model="ruleForm.${item.model}" type="date" placeholder="${item.placeholder}" />`
            break;
          case 'timeSelect':
            result += `<el-time-picker v-model="ruleForm.${item.model}" placeholder="${item.placeholder}" />`
            break;
          case 'switch':
            result += `<el-switch v-model="ruleForm.${item.model}" />`
            break;
          case 'checkBox':
            if (item.data) {
              result += `<el-checkbox-group v-model="ruleForm.${item.model}"> <el-checkbox v-for="(item, index) in ${item.data}" :key="index" :label="item.value">{{item.label}}</el-checkbox> </el-checkbox-group>`
            } else {
              result += `<el-checkbox-group v-model="ruleForm.${item.model}"> <el-checkbox label="复选框 A"></el-checkbox> </el-checkbox-group>`
            }
            break;
          case 'radio':
            if (item.data) {
              result += `<el-radio-group v-model="ruleForm.${item.model}"> <el-radio v-for="(item, index) in ${item.data}" :key="index" :label="item.value">{{item.label}}</el-radio> </el-radio-group>`
            } else {
              result += `<el-radio-group v-model="ruleForm.${item.model}"> <el-radio :label="3">备选项</el-radio> </el-radio-group>`
            }
            break;
          case 'textarea':
            result += `<el-input type="textarea" :rows="3" placeholder="${item.placeholder}" v-model="ruleForm.${item.model}" />`
            break;
          case 'buttonGroup':
            item.btns.map(i => {
              result += `<el-button type="${i.btnType}">${i.btnName}</el-button>`
            })
            break;

          default:
            break;
        }
        result += `</el-form-item>`
        return result
      }
      formData(item) {
        if (item.type !== 'buttonGroup' && item.model) {
          return `${item.model}: '',
          `
        }
        return ''
      }
      data(item) {
        if (item.type !== 'buttonGroup' && item.data) {
          return `${item.data}: [],
          `
        }
        return ''
      }
      methods(item) {
        let result = `{}`
        if (item.type === 'buttonGroup') {
          result = `{
            handleSubmitForm() {
              this.$refs.ruleForm.validate((valid) => {
                if (!valid) {
                  return
                }
                // do something...
              })
            }
          }`
        }
        return result
      }
    }
    this.$create = new Create()

    // 事件方法
    function moduleRender() {
      const modules = document.querySelector('#modules-box .modules')
      for (const key in moduleDom) {
        if (Object.hasOwnProperty.call(moduleDom, key)) {
          const dom = moduleDom[key];
          const dataDom = dom.replaceAll('$clickEvent', `addPreviewArea('${key}')`).replaceAll('$label', key)
          modules.innerHTML += dataDom
        }
      }
    }

    function onDialogConfirm() {
      if (typeof dialogObj.success === 'function') {
        dialogObj.success()
        hideDialog()
      } else {
        hideDialog()
      }
    }
    function onDialogCancel() {
      if (typeof dialogObj.fail === 'function') {
        dialogObj.fail()
        hideDialog()
      } else {
        hideDialog()
      }
    }
    function showDialog(popObj) {
      Object.assign(dialogObj, popObj)
      const dialogs = document.querySelectorAll('.dialogsModel')
      const dialogTitle = document.querySelector('#dialogTitle')
      const dialogContent = document.querySelector('#dialogContent')
      dialogTitle.innerHTML = dialogObj.title
      dialogContent.innerHTML = dialogObj.content
      dialogs.forEach(item => {
        item.style.display = 'block'
      })
    }
    function hideDialog() {
      const dialogs = document.querySelectorAll('.dialogsModel')
      const dialogTitle = document.querySelectorAll('#dialogTitle')
      const dialogContent = document.querySelector('#dialogContent')
      dialogTitle.innerHTML = ''
      dialogContent.innerHTML = ''
      dialogs.forEach(item => {
        item.style.display = 'none'
      })
      dialogObj = {
        title: '',
        content: '',
        success: null,
        fail: null
      }
    }
    function onGenerateCode() {
      showDialog({
        title: '提示',
        content: '正在生成代码，是否继续',
        success: () => {
          previewDomList.forEach(item => {
            __$data += this.$create.data(item)
          })
          __$data += `rules: {},
          ruleForm: {
            `
          previewDomList.forEach(item => {
            __$template += this.$create.template(item)
            __$data += this.$create.formData(item)
            __$methods = this.$create.methods(item)
          })
          __$data += `}`
          codeStr = codeStr.replaceAll('__$template', __$template).replaceAll('__$data', __$data).replaceAll('__$methods', __$methods)
          copy(codeStr)
        }
      })
    }
    function copy(content) {
      navigator.clipboard.writeText(content)
        .then(() => {
          this.$message.success('复制成功')
        })
        .catch(err => {
          this.$message.error('复制失败请重试')
        })
    }
    function addPreviewArea(type) {
      const btns = [{ btnName: '提交', btnType: 'primary', index: 1 }, { btnName: '取消', btnType: 'default', index: 2 }]
      const dataItem = { type: type, label: type, data: '', model: '', placeholder: '', startPlaceholder: '', endPlaceholder: '', btns: [] }
      if (type === 'buttonGroup') dataItem.btns = JSON.parse(JSON.stringify(btns))
      previewDomList.push(dataItem)
      previewRender()
    }
    function removePreviewArea() {
      showDialog({
        content: '确认要删除选中元素吗？',
        success: () => {
          const previewItems = document.querySelectorAll('#preview-area .module-item')
          for (let index = 0; index < previewItems.length; index++) {
            const node = previewItems[index]
            if (node.getAttribute('class').indexOf('active') !== -1) {
              previewDomList.splice(index, 1)
              previewRender()
              break
            }
          }
        }
      })
    }
    function onRemoveBtnItem(e) {
      onChangeAttr()
      const currentIndex = e.getAttribute('index')
      previewDomList[currentActiveIndex].btns.splice(currentIndex, 1)
      previewRender()
    }
    function onPushBtnInBtns() {
      previewDomList[currentActiveIndex].btns.push({
        btnName: '',
        btnType: ''
      })
      previewRender()
    }
    function onChangeAttr() {
      const previewItems = document.querySelectorAll('#preview-area .module-item')
      const configurations = document.querySelectorAll('#configuration .configuration-item')
      const configurationObj = {}
      // 如果当前选中元素为按钮需要另外处理
      if (previewDomList[currentActiveIndex].type === "buttonGroup") {
        const buttonGroups = document.querySelectorAll('#configuration .btn-group')
        for (let index = 0; index < buttonGroups.length; index++) {
          const node = buttonGroups[index]
          const inputValue = node.querySelectorAll('.input')
          previewDomList[currentActiveIndex].btns[index].btnName = inputValue[0].value
          previewDomList[currentActiveIndex].btns[index].btnType = inputValue[1].value
        }
      } else {
        for (let index = 0; index < configurations.length; index++) {
          const node = configurations[index]
          const ipt = node.querySelector('.val .input')
          const label = ipt.getAttribute('data-key')
          const val = ipt.value
          configurationObj[label] = val
        }
      }
      for (let index = 0; index < previewItems.length; index++) {
        const node = previewItems[index]
        if (node.getAttribute('class').indexOf('active') !== -1) {
          Object.assign(previewDomList[index], configurationObj)
          previewRender()
          break
        }
      }
      this.$message.success('属性保存成功')
    }
    function previewRender() {
      const area = document.querySelector('#preview-area')

      area.innerHTML = ''
      previewDomList.forEach((item, index) => {
        const domStr = moduleDom[item.type].replaceAll('$label', item.label)
          .replaceAll('$index', index)
          .replaceAll('$clickEvent', `selectorAttr(this, '${item.type}')`)
        area.innerHTML += domStr
        if (index === previewDomList.length - 1 && currentActiveIndex === null) {
          currentActiveIndex = index
        }
      })
      const modules = document.querySelectorAll('#preview-area .module-item')
      if (modules[currentActiveIndex]) {
        modules[currentActiveIndex].classList.add('active')
      } else if (modules.length) {
        currentActiveIndex = 0
        modules[currentActiveIndex].classList.add('active')
      } else {
        currentActiveIndex = null
        return
      }
      const previewItems = document.querySelectorAll('#preview-area .module-item')
      selectorAttr(previewItems[currentActiveIndex], previewDomList[currentActiveIndex].type)
    }
    function selectorAttr(e, type) {
      const configuration = document.querySelector('#configuration')
      const previewItems = document.querySelectorAll('#preview-area .module-item')
      // 在切换预览时, 自动保存属性
      const configurations = configuration.querySelectorAll('.configuration-item')
      const configurationObj = {}
      // 如果当前选中元素为按钮需要另外处理
      if (previewDomList[currentActiveIndex].type === "buttonGroup") {
        const buttonGroups = document.querySelectorAll('#configuration .btn-group')
        for (let index = 0; index < buttonGroups.length; index++) {
          const node = buttonGroups[index]
          const inputValue = node.querySelectorAll('.input')
          previewDomList[currentActiveIndex].btns[index].btnName = inputValue[0].value
          previewDomList[currentActiveIndex].btns[index].btnType = inputValue[1].value
        }
      } else {
        for (let index = 0; index < configurations.length; index++) {
          const node = configurations[index]
          const ipt = node.querySelector('.val .input')
          const label = ipt.getAttribute('data-key')
          const val = ipt.value
          configurationObj[label] = val
        }
      }
      previewItems.forEach((item, index) => {
        if (item.getAttribute('class').indexOf('active') !== -1) {
          Object.assign(previewDomList[index], configurationObj)
        }
        item.classList.remove('active')
      })
      e.classList.add('active')
      currentActiveIndex = e.getAttribute('index')
      configuration.innerHTML = ''
      selectorEnum[type].forEach((item, index) => {
        let dataStr = configDom[item].replaceAll('$value', previewDomList[currentActiveIndex][item])
        // 按钮组表现形式不同
        if (previewDomList[currentActiveIndex].btns.length) {
          previewDomList[currentActiveIndex].btns.map((item, index) => {
            let itemDom = configDom.btnItem.replaceAll('selected', "")
            itemDom = configDom.btnItem.replaceAll('$nameValue', item.btnName).replaceAll(`value="${item.btnType}"`, `value="${item.btnType}" selected`).replaceAll('$index', index)
            dataStr += itemDom
          })
        }
        configuration.innerHTML += dataStr
      })
    }
    moduleRender()
  </script>
</body>

</html>